package com.hbisoft.pickit;

import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.ability.DataUriUtils;
import ohos.app.Context;
import ohos.data.dataability.DataAbilityPredicates;
import ohos.data.resultset.ResultSet;
import ohos.media.photokit.metadata.AVStorage;
import ohos.utils.net.Uri;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

// 查询数据操作工具类
public class Utils {

    private static String failReason;

    private static final String PATH_DOCUMENT = "document";

    private static final String PATH_TREE = "tree";

    private static final String DISPLAY_NAME = "_display_name";

    private static final String DOCUMENTSTRING = "content://com.android.externalstorage.documents/document/primary";

    private static final String STORAGESTRING = "/storage/emulated/0/";

    static String errorReason() {
        return failReason;
    }

    /**
     * Main method use to translate uri to file real path
     *
     * @param context context
     * @param uri     file's uri
     * @return the real path of select file
     */
    static String getRealPathFromURI_API19(final Context context, final Uri uri) {
        String scheme = uri.getScheme();
        if (isDocumentUri(uri)) {
            if (isExternalStorageDocument(uri)) {
                final String docId = getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                if ("primary".equalsIgnoreCase(type)) {
                    if (split.length > 1) {
                        return context.getFilesDir() + File.separator + split[1];
                    } else {
                        return context.getFilesDir() + File.separator;
                    }
                } else {
                    // Some devices does not allow access to the SD Card using the UID, for example /storage/6551-1152/folder/video.mp4
                    // Instead, we first have to get the name of the SD Card, for example /storage/sdcard1/folder/video.mp4

                    // We first have to check if the device allows this access
                    File file = new File("storage" + File.separator + docId.replace(":", "/"));
                    if (file.exists()) {
                        return File.separator + "storage/" + File.separator + docId.replace(":", "/");
                    }
                    // If the file is not available, we have to get the name of the SD Card, have a look at SDUtils
                    String[] availableExternalStorages = SDUtil.getStorageDirectories(context);
                    String root = "";
                    for (String str : availableExternalStorages) {
                        if (split[1].startsWith("/")) {
                            root = str + split[1];
                        } else {
                            root = str + File.separator + split[1];
                        }
                    }
                    if (root.contains(type)) {
                        return "storage" + File.separator + docId.replace(":", "/");
                    } else {
                        if (root.startsWith("/storage/") || root.startsWith("storage/")) {
                            return root;
                        } else if (root.startsWith("/")) {
                            return File.separator + "storage" + root;
                        } else {
                            return File.separator + "storage" + File.separator + root;
                        }
                    }
                }

            } else if (isRawDownloadsDocument(uri)) {
                String fileName = getFilePath(context, uri);
                String subFolderName = getSubFolders(uri);

                if (fileName != null) {
                    return context.getFilesDir().toString() + File.separator + "Download" + File.separator + subFolderName + fileName;
                }
                String id = getDocumentId(uri);

                final Uri contentUri = DataUriUtils.attachId(Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));
                return getDataColumn(context, contentUri, null, null);
            } else if (isDownloadsDocument(uri)) {
                String fileName = getFilePath(context, uri);

                if (fileName != null) {
                    return context.getFilesDir().toString() + File.separator + "Download" + File.separator + fileName;
                }
                String id = getDocumentId(uri);
                if (id.startsWith("raw:")) {
                    id = id.replaceFirst("raw:", "");
                    File file = new File(id);
                    if (file.exists())
                        return id;
                }
                if (id.startsWith("raw%3A%2F")) {
                    id = id.replaceFirst("raw%3A%2F", "");
                    File file = new File(id);
                    if (file.exists())
                        return id;
                }
                final Uri contentUri = DataUriUtils.attachId(Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));
                return getDataColumn(context, contentUri, null, null);
            } else if (isMediaDocument(uri)) {
                final String docId = getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equalsIgnoreCase(type)) {
                    contentUri = AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI;
                } else if ("video".equalsIgnoreCase(type)) {
                    contentUri = AVStorage.Video.Media.EXTERNAL_DATA_ABILITY_URI;
                } else if ("audio".equalsIgnoreCase(type)) {
                    contentUri = AVStorage.Audio.Media.EXTERNAL_DATA_ABILITY_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{
                        split[1]
                };

                return getDataColumn(context, contentUri, selection, selectionArgs);
            }
        } else if ("content".equalsIgnoreCase(scheme) || "dataability".equalsIgnoreCase(scheme)) {
            if (isGooglePhotosUri(uri)) {
                return uri.getLastPath();
            }

            if (getDataColumn(context, uri, null, null) == null) {
                failReason = "dataReturnedNull";
            }
            return getDataColumn(context, uri, null, null);
        } else if ("file".equalsIgnoreCase(scheme)) {
            return uri.getDecodedPath();
        }

        return null;
    }

    /**
     * Test if the given URI represents
     *
     * @param uri
     * @return boolean
     */
    private static boolean isDocumentUri(Uri uri) {
        if (isContentUri(uri)) {
            final List<String> paths = uri.getDecodedPathList();
            if (paths.size() == 2) {
                return PATH_DOCUMENT.equals(paths.get(0));
            } else if (paths.size() == 4) {
                return PATH_TREE.equals(paths.get(0)) && PATH_DOCUMENT.equals(paths.get(2));
            }
        }
        return false;
    }

    private static boolean isContentUri(Uri uri) {
        return uri != null && "content".equals(uri.getScheme());
    }

    /**
     * Extract the ID from the given URI.
     *
     * @param documentUri
     * @return String
     * @throws IllegalArgumentException
     */
    private static String getDocumentId(Uri documentUri) {
        final List<String> paths = documentUri.getDecodedPathList();
        if (paths.size() >= 2 && PATH_DOCUMENT.equals(paths.get(0))) {
            return paths.get(1);
        }
        if (paths.size() >= 4 && PATH_TREE.equals(paths.get(0))
                && PATH_DOCUMENT.equals(paths.get(2))) {
            return paths.get(3);
        }
        throw new IllegalArgumentException("Invalid URI: " + documentUri);
    }

    private static String getSubFolders(Uri uri) {
        String replaceChars = String.valueOf(uri).replace("%2F", "/").replace("%20", " ").replace("%3A", ":");
        String[] bits = replaceChars.split("/");
        String sub5 = bits[bits.length - 2];
        String sub4 = bits[bits.length - 3];
        String sub3 = bits[bits.length - 4];
        String sub2 = bits[bits.length - 5];
        String sub1 = bits[bits.length - 6];
        if (sub1.equals("Download")) {
            return sub2 + File.separator + sub3 + File.separator + sub4 + File.separator + sub5 + File.separator;
        } else if (sub2.equals("Download")) {
            return sub3 + File.separator + sub4 + File.separator + sub5 + File.separator;
        } else if (sub3.equals("Download")) {
            return sub4 + File.separator + sub5 + File.separator;
        } else if (sub4.equals("Download")) {
            return sub5 + File.separator;
        } else {
            return "";
        }
    }

    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
        if (null == selection || selection.length() == 0) {
            if (null != uri) {
                if (isDocumentUri(uri.toString()) || isStorageUri(uri.toString())) {
                    String str = null;
                    String urlEncoderString = urldecoderstring(uri.toString());
                    if (isDocumentUri(uri.toString())) {
                        str = urlEncoderString.replace(DOCUMENTSTRING + ":", STORAGESTRING);
                    } else if (isStorageUri(uri.toString())) {
                        int pos = urlEncoderString.indexOf(STORAGESTRING);
                        str = urlEncoderString.substring(pos);
                    } else {
                        Logger.getLogger("Utils").log(Level.INFO, "unknown mediaUri");
                    }
                    try {
                        return new File(str).getCanonicalPath();
                    } catch (IOException e) {
                        Logger.getLogger("Utils").log(Level.INFO, "getCanonicalPath IOException" + e.getMessage());
                        return null;
                    }
                } else {
                    Uri mediaUri = null;
                    String mediaId = getNumbers(uri.toString());
                    if (uri.toString().contains("image")) {
                        mediaUri = Uri.appendEncodedPathToUri(AVStorage.Images.Media
                                .EXTERNAL_DATA_ABILITY_URI, mediaId);
                    } else if (uri.toString().contains("audio")) {
                        mediaUri = Uri.appendEncodedPathToUri(AVStorage.Audio.Media
                                .EXTERNAL_DATA_ABILITY_URI, mediaId);
                    } else if (uri.toString().contains("video")) {
                        mediaUri = Uri.appendEncodedPathToUri(AVStorage.Video.Media
                                .EXTERNAL_DATA_ABILITY_URI, mediaId);
                    } else if (uri.toString().contains("file")) {
                        mediaUri = Uri.parse(uri.toString()
                                .replace("content://", "dataability:///"));
                    } else {
                        Logger.getLogger("Utils").log(Level.INFO, "unknown mediaUri");
                    }
                    try {
                        ResultSet resultSet = DataAbilityHelper.creator(context).query(mediaUri, null, null);
                        while (resultSet.goToNextRow()) {
                            String path = resultSet.getString(resultSet
                                    .getColumnIndexForName(AVStorage.Video.Media.DATA));
                            resultSet.close();
                            return path;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        } else {
            ResultSet cursor = null;
            final String column = "_data";
            final String[] projection = {column};
            try {
                DataAbilityPredicates predicates = new DataAbilityPredicates(selection);
                if (selectionArgs != null && selectionArgs.length > 0) {
                    predicates.setWhereArgs(Arrays.asList(selectionArgs));
                } else {
                    predicates.setWhereArgs(null);
                }
                cursor = DataAbilityHelper.creator(context).query(uri, projection, predicates);
                if (cursor != null && cursor.goToFirstRow()) {
                    final int index = cursor.getColumnIndexForName(column);
                    return cursor.getString(index);
                }
            } catch (Exception e) {
                failReason = e.getMessage();
            } finally {
                if (cursor != null)
                    cursor.close();
            }
        }
        return null;
    }


    private static String getFilePath(Context context, Uri uri) {
        ResultSet cursor = null;
        final String[] projection = {DISPLAY_NAME};
        try {
            cursor = DataAbilityHelper.creator(context).query(uri, projection, new DataAbilityPredicates());
            if (cursor != null && cursor.goToFirstRow()) {
                final int index = cursor.getColumnIndexForName(DISPLAY_NAME);
                return cursor.getString(index);
            }
        } catch (Exception e) {
            failReason = e.getMessage();
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }

    /**
     * 是否是DocumentUri
     *
     * @param uriStr uri路径的String类型
     * @return boolean 结论
     */
    public static boolean isDocumentUri(String uriStr) {
        return uriStr.startsWith(DOCUMENTSTRING);
    }

    /**
     * 是否是StorageUri
     *
     * @param strUri uri路径的String类型
     * @return boolean 结论
     */
    public static boolean isStorageUri(String strUri) {
        return strUri.contains(STORAGESTRING);
    }

    /**
     * Uri解码
     *
     * @param str uri
     * @return result 解码后的URL
     */
    public static String urldecoderstring(String str) {
        String result = "";
        if (null == str) {
            return "";
        }
        try {
            result = java.net.URLDecoder.decode(str, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 获取mediaId
     *
     * @param content uriStr
     * @return mediaID 资源ID
     */
    public static String getNumbers(String content) {
        String str = content.replaceAll(".*[^\\d](?=(\\d+))", "");
        return str;
    }

    private static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getDecodedAuthority());
    }


    private static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getDecodedAuthority());
    }

    private static boolean isRawDownloadsDocument(Uri uri) {
        String uriToString = String.valueOf(uri);
        return uriToString.contains("com.android.providers.downloads.documents/document/raw");
    }

    private static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getDecodedAuthority());
    }


    private static boolean isGooglePhotosUri(Uri uri) {
        return "com.google.android.apps.photos.content".equals(uri.getDecodedAuthority());
    }

}
